#include <openssl/evp.h>
#include <openssl/aes.h>

/*
*****************************************************************************************
*   函 数 名: aes_encrypt_string
*   功能说明: AES加密字符串
*   形    参:   _pPassword  :   密码
*               _pInput     :   输入数据
*               _InLen      :   输入数据长度
*               _pOutBuf    :   输出AES编码数据
*               _pOutLen    :   输出AES编码数据长度
*   返 回 值: 0：成功, -1：失败
*****************************************************************************************
*/
int aes_encrypt_string(char *_pPassword, char *_pInput, int _InLen, char *_pOutBuf, int *_pOutLen)
{
    // 上下文结构
    EVP_CIPHER_CTX *pEn_ctx = NULL;

    int ret = -1;
    int flen = 0, outlen = 0;
    int i, nrounds = 1;

    // 存储秘钥和初始化向量
    unsigned char key[32] = {};
    unsigned char iv[32] = {};

    // 参数判断
    if (_pPassword == NULL || _pInput == NULL || _pOutBuf == NULL || _pOutLen == NULL) {
        return ret;
    }

    // 设置使用 256 位密钥长度的 AES 加密算法，并采用 CBC 模式。
    const EVP_CIPHER *cipherType = EVP_aes_256_cbc();
    if( cipherType == NULL ){
        goto clean;
    }

    /*
    * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
    * nrounds is the number of times the we hash the material. More rounds are more secure but
    * slower.
    */
    // 通过输入密码产生密钥key和初始化向量iv
    i = EVP_BytesToKey(cipherType, EVP_md5(), NULL, _pPassword, strlen(_pPassword), nrounds, key, iv);
    if (i != 32) {
        printf("Key size is %d bits - should be 256 bits\n", i);
        goto clean;
    }

    pEn_ctx = EVP_CIPHER_CTX_new();                             //创建加密上下文
    EVP_CIPHER_CTX_init(pEn_ctx);                               //初始化 EVP_CIPHER_CTX 上下文
    EVP_EncryptInit_ex(pEn_ctx, cipherType, NULL, key, iv);     //初始化加密操作

    /* Update cipher text */
    if (!EVP_EncryptUpdate(pEn_ctx, (unsigned char*)_pOutBuf, &outlen,(unsigned char*)_pInput, _InLen)) {   //处理数据
        perror("\n Error,ENCRYPR_UPDATE:");
        goto clean;
    }

    /* updates the remaining bytes */
    if (!EVP_EncryptFinal_ex(pEn_ctx, (unsigned char*)(_pOutBuf + outlen), &flen)) {    //完成加密操作，处理剩余字节
        perror("\n Error,ENCRYPT_FINAL:");
        goto clean;
    }

    *_pOutLen = outlen + flen;

    ret = 0;    /* SUCCESS */

clean:
    // 清理内存
    if( pEn_ctx )
        EVP_CIPHER_CTX_cleanup(pEn_ctx);
    if( pEn_ctx )
        EVP_CIPHER_CTX_free(pEn_ctx);

    return ret;
}

int main(int argc, char *argv[])
{
    if( argc < 3 )
    {
        printf("Usage: %s <STRING> <PASSWORD>\n", argv[0]);
        return -1;
    }
​
    int i;
    char acString[96]    = {0};
    char acPassword[96]  = {0};
    char acEncrypt[2048] = {0};
    char acDecrypt[2048] = {0};
    int enLen = 0, deLen = 0;

    strcpy(acString, argv[1]);
    strcpy(acPassword, argv[2]);

    /* 打印加密的字符串和密码 */
    printf("===========Org=============\n");
    printf("password: %s\n", acPassword);
    printf("string: %s\n", acString);
    printf("slen: %d\n", strlen(acString));
    printf("===========================\n\n");
​
    /* AES加密 */
    printf("===========ENC=============\n");
    i = aes_encrypt_string( acPassword, acString, strlen(acString), acEncrypt, &enLen );
    if( i < 0 ){
        printf("enc error.\n");
        return -1;
    }
    printf("Enc: %s\n", acEncrypt);                                                           //打印加密数据
    printf("elen: %d\n", enLen);
    printf("===========================\n\n");
​
    /* AES解密 */
    printf("============DEC=============\n");
    i = aes_decrypt_string( acPassword, acEncrypt, enLen, acDecrypt, &deLen );
    if( i < 0 ){
        printf("dec error.\n");
        return -1;
    }

    acDecrypt[deLen] = 0;
    printf("Dec: %s\n", acDecrypt);
    //打印解密数据
    printf("dlen: %d\n", deLen);
    printf("===========================\n\n");

    return 0;
}